Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
news
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Sartika Aritonang
news
Commits
16da014c
Commit
16da014c
authored
May 29, 2020
by
Sartika Aritonang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Upload New File
parent
291af141
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
491 additions
and
0 deletions
+491
-0
sandbox.py
stbi/Lib/site-packages/setuptools/sandbox.py
+491
-0
No files found.
stbi/Lib/site-packages/setuptools/sandbox.py
0 → 100644
View file @
16da014c
import
os
import
sys
import
tempfile
import
operator
import
functools
import
itertools
import
re
import
contextlib
import
pickle
import
textwrap
from
setuptools.extern
import
six
from
setuptools.extern.six.moves
import
builtins
,
map
import
pkg_resources.py31compat
if
sys
.
platform
.
startswith
(
'java'
):
import
org.python.modules.posix.PosixModule
as
_os
else
:
_os
=
sys
.
modules
[
os
.
name
]
try
:
_file
=
file
except
NameError
:
_file
=
None
_open
=
open
from
distutils.errors
import
DistutilsError
from
pkg_resources
import
working_set
__all__
=
[
"AbstractSandbox"
,
"DirectorySandbox"
,
"SandboxViolation"
,
"run_setup"
,
]
def
_execfile
(
filename
,
globals
,
locals
=
None
):
"""
Python 3 implementation of execfile.
"""
mode
=
'rb'
with
open
(
filename
,
mode
)
as
stream
:
script
=
stream
.
read
()
if
locals
is
None
:
locals
=
globals
code
=
compile
(
script
,
filename
,
'exec'
)
exec
(
code
,
globals
,
locals
)
@contextlib.contextmanager
def
save_argv
(
repl
=
None
):
saved
=
sys
.
argv
[:]
if
repl
is
not
None
:
sys
.
argv
[:]
=
repl
try
:
yield
saved
finally
:
sys
.
argv
[:]
=
saved
@contextlib.contextmanager
def
save_path
():
saved
=
sys
.
path
[:]
try
:
yield
saved
finally
:
sys
.
path
[:]
=
saved
@contextlib.contextmanager
def
override_temp
(
replacement
):
"""
Monkey-patch tempfile.tempdir with replacement, ensuring it exists
"""
pkg_resources
.
py31compat
.
makedirs
(
replacement
,
exist_ok
=
True
)
saved
=
tempfile
.
tempdir
tempfile
.
tempdir
=
replacement
try
:
yield
finally
:
tempfile
.
tempdir
=
saved
@contextlib.contextmanager
def
pushd
(
target
):
saved
=
os
.
getcwd
()
os
.
chdir
(
target
)
try
:
yield
saved
finally
:
os
.
chdir
(
saved
)
class
UnpickleableException
(
Exception
):
"""
An exception representing another Exception that could not be pickled.
"""
@staticmethod
def
dump
(
type
,
exc
):
"""
Always return a dumped (pickled) type and exc. If exc can't be pickled,
wrap it in UnpickleableException first.
"""
try
:
return
pickle
.
dumps
(
type
),
pickle
.
dumps
(
exc
)
except
Exception
:
# get UnpickleableException inside the sandbox
from
setuptools.sandbox
import
UnpickleableException
as
cls
return
cls
.
dump
(
cls
,
cls
(
repr
(
exc
)))
class
ExceptionSaver
:
"""
A Context Manager that will save an exception, serialized, and restore it
later.
"""
def
__enter__
(
self
):
return
self
def
__exit__
(
self
,
type
,
exc
,
tb
):
if
not
exc
:
return
# dump the exception
self
.
_saved
=
UnpickleableException
.
dump
(
type
,
exc
)
self
.
_tb
=
tb
# suppress the exception
return
True
def
resume
(
self
):
"restore and re-raise any exception"
if
'_saved'
not
in
vars
(
self
):
return
type
,
exc
=
map
(
pickle
.
loads
,
self
.
_saved
)
six
.
reraise
(
type
,
exc
,
self
.
_tb
)
@contextlib.contextmanager
def
save_modules
():
"""
Context in which imported modules are saved.
Translates exceptions internal to the context into the equivalent exception
outside the context.
"""
saved
=
sys
.
modules
.
copy
()
with
ExceptionSaver
()
as
saved_exc
:
yield
saved
sys
.
modules
.
update
(
saved
)
# remove any modules imported since
del_modules
=
(
mod_name
for
mod_name
in
sys
.
modules
if
mod_name
not
in
saved
# exclude any encodings modules. See #285
and
not
mod_name
.
startswith
(
'encodings.'
)
)
_clear_modules
(
del_modules
)
saved_exc
.
resume
()
def
_clear_modules
(
module_names
):
for
mod_name
in
list
(
module_names
):
del
sys
.
modules
[
mod_name
]
@contextlib.contextmanager
def
save_pkg_resources_state
():
saved
=
pkg_resources
.
__getstate__
()
try
:
yield
saved
finally
:
pkg_resources
.
__setstate__
(
saved
)
@contextlib.contextmanager
def
setup_context
(
setup_dir
):
temp_dir
=
os
.
path
.
join
(
setup_dir
,
'temp'
)
with
save_pkg_resources_state
():
with
save_modules
():
hide_setuptools
()
with
save_path
():
with
save_argv
():
with
override_temp
(
temp_dir
):
with
pushd
(
setup_dir
):
# ensure setuptools commands are available
__import__
(
'setuptools'
)
yield
def
_needs_hiding
(
mod_name
):
"""
>>> _needs_hiding('setuptools')
True
>>> _needs_hiding('pkg_resources')
True
>>> _needs_hiding('setuptools_plugin')
False
>>> _needs_hiding('setuptools.__init__')
True
>>> _needs_hiding('distutils')
True
>>> _needs_hiding('os')
False
>>> _needs_hiding('Cython')
True
"""
pattern
=
re
.
compile
(
r'(setuptools|pkg_resources|distutils|Cython)(\.|$)'
)
return
bool
(
pattern
.
match
(
mod_name
))
def
hide_setuptools
():
"""
Remove references to setuptools' modules from sys.modules to allow the
invocation to import the most appropriate setuptools. This technique is
necessary to avoid issues such as #315 where setuptools upgrading itself
would fail to find a function declared in the metadata.
"""
modules
=
filter
(
_needs_hiding
,
sys
.
modules
)
_clear_modules
(
modules
)
def
run_setup
(
setup_script
,
args
):
"""Run a distutils setup script, sandboxed in its directory"""
setup_dir
=
os
.
path
.
abspath
(
os
.
path
.
dirname
(
setup_script
))
with
setup_context
(
setup_dir
):
try
:
sys
.
argv
[:]
=
[
setup_script
]
+
list
(
args
)
sys
.
path
.
insert
(
0
,
setup_dir
)
# reset to include setup dir, w/clean callback list
working_set
.
__init__
()
working_set
.
callbacks
.
append
(
lambda
dist
:
dist
.
activate
())
# __file__ should be a byte string on Python 2 (#712)
dunder_file
=
(
setup_script
if
isinstance
(
setup_script
,
str
)
else
setup_script
.
encode
(
sys
.
getfilesystemencoding
())
)
with
DirectorySandbox
(
setup_dir
):
ns
=
dict
(
__file__
=
dunder_file
,
__name__
=
'__main__'
)
_execfile
(
setup_script
,
ns
)
except
SystemExit
as
v
:
if
v
.
args
and
v
.
args
[
0
]:
raise
# Normal exit, just return
class
AbstractSandbox
:
"""Wrap 'os' module and 'open()' builtin for virtualizing setup scripts"""
_active
=
False
def
__init__
(
self
):
self
.
_attrs
=
[
name
for
name
in
dir
(
_os
)
if
not
name
.
startswith
(
'_'
)
and
hasattr
(
self
,
name
)
]
def
_copy
(
self
,
source
):
for
name
in
self
.
_attrs
:
setattr
(
os
,
name
,
getattr
(
source
,
name
))
def
__enter__
(
self
):
self
.
_copy
(
self
)
if
_file
:
builtins
.
file
=
self
.
_file
builtins
.
open
=
self
.
_open
self
.
_active
=
True
def
__exit__
(
self
,
exc_type
,
exc_value
,
traceback
):
self
.
_active
=
False
if
_file
:
builtins
.
file
=
_file
builtins
.
open
=
_open
self
.
_copy
(
_os
)
def
run
(
self
,
func
):
"""Run 'func' under os sandboxing"""
with
self
:
return
func
()
def
_mk_dual_path_wrapper
(
name
):
original
=
getattr
(
_os
,
name
)
def
wrap
(
self
,
src
,
dst
,
*
args
,
**
kw
):
if
self
.
_active
:
src
,
dst
=
self
.
_remap_pair
(
name
,
src
,
dst
,
*
args
,
**
kw
)
return
original
(
src
,
dst
,
*
args
,
**
kw
)
return
wrap
for
name
in
[
"rename"
,
"link"
,
"symlink"
]:
if
hasattr
(
_os
,
name
):
locals
()[
name
]
=
_mk_dual_path_wrapper
(
name
)
def
_mk_single_path_wrapper
(
name
,
original
=
None
):
original
=
original
or
getattr
(
_os
,
name
)
def
wrap
(
self
,
path
,
*
args
,
**
kw
):
if
self
.
_active
:
path
=
self
.
_remap_input
(
name
,
path
,
*
args
,
**
kw
)
return
original
(
path
,
*
args
,
**
kw
)
return
wrap
if
_file
:
_file
=
_mk_single_path_wrapper
(
'file'
,
_file
)
_open
=
_mk_single_path_wrapper
(
'open'
,
_open
)
for
name
in
[
"stat"
,
"listdir"
,
"chdir"
,
"open"
,
"chmod"
,
"chown"
,
"mkdir"
,
"remove"
,
"unlink"
,
"rmdir"
,
"utime"
,
"lchown"
,
"chroot"
,
"lstat"
,
"startfile"
,
"mkfifo"
,
"mknod"
,
"pathconf"
,
"access"
]:
if
hasattr
(
_os
,
name
):
locals
()[
name
]
=
_mk_single_path_wrapper
(
name
)
def
_mk_single_with_return
(
name
):
original
=
getattr
(
_os
,
name
)
def
wrap
(
self
,
path
,
*
args
,
**
kw
):
if
self
.
_active
:
path
=
self
.
_remap_input
(
name
,
path
,
*
args
,
**
kw
)
return
self
.
_remap_output
(
name
,
original
(
path
,
*
args
,
**
kw
))
return
original
(
path
,
*
args
,
**
kw
)
return
wrap
for
name
in
[
'readlink'
,
'tempnam'
]:
if
hasattr
(
_os
,
name
):
locals
()[
name
]
=
_mk_single_with_return
(
name
)
def
_mk_query
(
name
):
original
=
getattr
(
_os
,
name
)
def
wrap
(
self
,
*
args
,
**
kw
):
retval
=
original
(
*
args
,
**
kw
)
if
self
.
_active
:
return
self
.
_remap_output
(
name
,
retval
)
return
retval
return
wrap
for
name
in
[
'getcwd'
,
'tmpnam'
]:
if
hasattr
(
_os
,
name
):
locals
()[
name
]
=
_mk_query
(
name
)
def
_validate_path
(
self
,
path
):
"""Called to remap or validate any path, whether input or output"""
return
path
def
_remap_input
(
self
,
operation
,
path
,
*
args
,
**
kw
):
"""Called for path inputs"""
return
self
.
_validate_path
(
path
)
def
_remap_output
(
self
,
operation
,
path
):
"""Called for path outputs"""
return
self
.
_validate_path
(
path
)
def
_remap_pair
(
self
,
operation
,
src
,
dst
,
*
args
,
**
kw
):
"""Called for path pairs like rename, link, and symlink operations"""
return
(
self
.
_remap_input
(
operation
+
'-from'
,
src
,
*
args
,
**
kw
),
self
.
_remap_input
(
operation
+
'-to'
,
dst
,
*
args
,
**
kw
)
)
if
hasattr
(
os
,
'devnull'
):
_EXCEPTIONS
=
[
os
.
devnull
,]
else
:
_EXCEPTIONS
=
[]
class
DirectorySandbox
(
AbstractSandbox
):
"""Restrict operations to a single subdirectory - pseudo-chroot"""
write_ops
=
dict
.
fromkeys
([
"open"
,
"chmod"
,
"chown"
,
"mkdir"
,
"remove"
,
"unlink"
,
"rmdir"
,
"utime"
,
"lchown"
,
"chroot"
,
"mkfifo"
,
"mknod"
,
"tempnam"
,
])
_exception_patterns
=
[
# Allow lib2to3 to attempt to save a pickled grammar object (#121)
r'.*lib2to3.*\.pickle$'
,
]
"exempt writing to paths that match the pattern"
def
__init__
(
self
,
sandbox
,
exceptions
=
_EXCEPTIONS
):
self
.
_sandbox
=
os
.
path
.
normcase
(
os
.
path
.
realpath
(
sandbox
))
self
.
_prefix
=
os
.
path
.
join
(
self
.
_sandbox
,
''
)
self
.
_exceptions
=
[
os
.
path
.
normcase
(
os
.
path
.
realpath
(
path
))
for
path
in
exceptions
]
AbstractSandbox
.
__init__
(
self
)
def
_violation
(
self
,
operation
,
*
args
,
**
kw
):
from
setuptools.sandbox
import
SandboxViolation
raise
SandboxViolation
(
operation
,
args
,
kw
)
if
_file
:
def
_file
(
self
,
path
,
mode
=
'r'
,
*
args
,
**
kw
):
if
mode
not
in
(
'r'
,
'rt'
,
'rb'
,
'rU'
,
'U'
)
and
not
self
.
_ok
(
path
):
self
.
_violation
(
"file"
,
path
,
mode
,
*
args
,
**
kw
)
return
_file
(
path
,
mode
,
*
args
,
**
kw
)
def
_open
(
self
,
path
,
mode
=
'r'
,
*
args
,
**
kw
):
if
mode
not
in
(
'r'
,
'rt'
,
'rb'
,
'rU'
,
'U'
)
and
not
self
.
_ok
(
path
):
self
.
_violation
(
"open"
,
path
,
mode
,
*
args
,
**
kw
)
return
_open
(
path
,
mode
,
*
args
,
**
kw
)
def
tmpnam
(
self
):
self
.
_violation
(
"tmpnam"
)
def
_ok
(
self
,
path
):
active
=
self
.
_active
try
:
self
.
_active
=
False
realpath
=
os
.
path
.
normcase
(
os
.
path
.
realpath
(
path
))
return
(
self
.
_exempted
(
realpath
)
or
realpath
==
self
.
_sandbox
or
realpath
.
startswith
(
self
.
_prefix
)
)
finally
:
self
.
_active
=
active
def
_exempted
(
self
,
filepath
):
start_matches
=
(
filepath
.
startswith
(
exception
)
for
exception
in
self
.
_exceptions
)
pattern_matches
=
(
re
.
match
(
pattern
,
filepath
)
for
pattern
in
self
.
_exception_patterns
)
candidates
=
itertools
.
chain
(
start_matches
,
pattern_matches
)
return
any
(
candidates
)
def
_remap_input
(
self
,
operation
,
path
,
*
args
,
**
kw
):
"""Called for path inputs"""
if
operation
in
self
.
write_ops
and
not
self
.
_ok
(
path
):
self
.
_violation
(
operation
,
os
.
path
.
realpath
(
path
),
*
args
,
**
kw
)
return
path
def
_remap_pair
(
self
,
operation
,
src
,
dst
,
*
args
,
**
kw
):
"""Called for path pairs like rename, link, and symlink operations"""
if
not
self
.
_ok
(
src
)
or
not
self
.
_ok
(
dst
):
self
.
_violation
(
operation
,
src
,
dst
,
*
args
,
**
kw
)
return
(
src
,
dst
)
def
open
(
self
,
file
,
flags
,
mode
=
0
o777
,
*
args
,
**
kw
):
"""Called for low-level os.open()"""
if
flags
&
WRITE_FLAGS
and
not
self
.
_ok
(
file
):
self
.
_violation
(
"os.open"
,
file
,
flags
,
mode
,
*
args
,
**
kw
)
return
_os
.
open
(
file
,
flags
,
mode
,
*
args
,
**
kw
)
WRITE_FLAGS
=
functools
.
reduce
(
operator
.
or_
,
[
getattr
(
_os
,
a
,
0
)
for
a
in
"O_WRONLY O_RDWR O_APPEND O_CREAT O_TRUNC O_TEMPORARY"
.
split
()]
)
class
SandboxViolation
(
DistutilsError
):
"""A setup script attempted to modify the filesystem outside the sandbox"""
tmpl
=
textwrap
.
dedent
(
"""
SandboxViolation: {cmd}{args!r} {kwargs}
The package setup script has attempted to modify files on your system
that are not within the EasyInstall build area, and has been aborted.
This package cannot be safely installed by EasyInstall, and may not
support alternate installation locations even if you run its setup
script by hand. Please inform the package's author and the EasyInstall
maintainers to find out if a fix or workaround is available.
"""
)
.
lstrip
()
def
__str__
(
self
):
cmd
,
args
,
kwargs
=
self
.
args
return
self
.
tmpl
.
format
(
**
locals
())
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment