4
4
import os
5
5
import struct
6
6
import subprocess
7
+ from abc import ABCMeta , abstractmethod
7
8
from textwrap import dedent
8
9
9
- from virtualenv .create .via_global_ref .builtin .cpython .common import CPythonPosix
10
- from virtualenv .create .via_global_ref .builtin .ref import PathRefToDest
10
+ from six import add_metaclass
11
+
12
+ from virtualenv .create .via_global_ref .builtin .ref import ExePathRefToDest , PathRefToDest
11
13
from virtualenv .util .path import Path
12
14
from virtualenv .util .six import ensure_text
13
15
14
- from .cpython2 import CPython2 , is_mac_os_framework
16
+ from .common import CPython , CPythonPosix , is_mac_os_framework
17
+ from .cpython2 import CPython2
18
+ from .cpython3 import CPython3
15
19
16
20
17
- class CPython2macOsFramework (CPython2 , CPythonPosix ):
21
+ @add_metaclass (ABCMeta )
22
+ class CPythonmacOsFramework (CPython ):
18
23
@classmethod
19
24
def can_describe (cls , interpreter ):
20
- return is_mac_os_framework (interpreter ) and super (CPython2macOsFramework , cls ).can_describe (interpreter )
21
-
22
- def create (self ):
23
- super (CPython2macOsFramework , self ).create ()
24
-
25
- # change the install_name of the copied python executable
26
- current = os .path .join (self .interpreter .prefix , "Python" )
27
- fix_mach_o (str (self .exe ), current , "@executable_path/../.Python" , self .interpreter .max_size )
25
+ return is_mac_os_framework (interpreter ) and super (CPythonmacOsFramework , cls ).can_describe (interpreter )
28
26
29
27
@classmethod
30
28
def sources (cls , interpreter ):
31
- for src in super (CPython2macOsFramework , cls ).sources (interpreter ):
29
+ for src in super (CPythonmacOsFramework , cls ).sources (interpreter ):
32
30
yield src
33
-
34
- # landmark for exec_prefix
35
- name = "lib-dynload"
36
- yield PathRefToDest (interpreter .stdlib_path (name ), dest = cls .to_stdlib )
37
-
38
- # this must symlink to the host prefix Python
39
- marker = Path (interpreter .prefix ) / "Python"
40
- ref = PathRefToDest (marker , dest = lambda self , _ : self .dest / ".Python" , must_symlink = True )
31
+ # add a symlink to the host python image
32
+ ref = PathRefToDest (cls .image_ref (interpreter ), dest = lambda self , _ : self .dest / ".Python" , must_symlink = True )
41
33
yield ref
42
34
35
+ def create (self ):
36
+ super (CPythonmacOsFramework , self ).create ()
37
+
38
+ # change the install_name of the copied python executables
39
+ target = "@executable_path/../.Python"
40
+ current = self .current_mach_o_image_path ()
41
+ for src in self ._sources :
42
+ if isinstance (src , ExePathRefToDest ):
43
+ if src .must_copy or not self .symlinks :
44
+ exes = [self .bin_dir / src .base ]
45
+ if not self .symlinks :
46
+ exes .extend (self .bin_dir / a for a in src .aliases )
47
+ for exe in exes :
48
+ fix_mach_o (str (exe ), current , target , self .interpreter .max_size )
49
+
43
50
@classmethod
44
51
def _executables (cls , interpreter ):
45
- for _ , targets in super (CPython2macOsFramework , cls )._executables (interpreter ):
52
+ for _ , targets in super (CPythonmacOsFramework , cls )._executables (interpreter ):
46
53
# Make sure we use the embedded interpreter inside the framework, even if sys.executable points to the
47
54
# stub executable in ${sys.prefix}/bin.
48
55
# See http://groups.google.com/group/python-virtualenv/browse_thread/thread/17cab2f85da75951
49
56
fixed_host_exe = Path (interpreter .prefix ) / "Resources" / "Python.app" / "Contents" / "MacOS" / "Python"
50
57
yield fixed_host_exe , targets
51
58
59
+ @abstractmethod
60
+ def current_mach_o_image_path (self ):
61
+ raise NotImplementedError
62
+
63
+ @classmethod
64
+ def image_ref (cls , interpreter ):
65
+ raise NotImplementedError
66
+
67
+
68
+ class CPython2macOsFramework (CPythonmacOsFramework , CPython2 , CPythonPosix ):
69
+ @classmethod
70
+ def image_ref (cls , interpreter ):
71
+ return Path (interpreter .prefix ) / "Python"
72
+
73
+ def current_mach_o_image_path (self ):
74
+ return os .path .join (self .interpreter .prefix , "Python" )
75
+
76
+ @classmethod
77
+ def sources (cls , interpreter ):
78
+ for src in super (CPython2macOsFramework , cls ).sources (interpreter ):
79
+ yield src
80
+ name = "lib-dynload" # landmark for exec_prefix
81
+ yield PathRefToDest (interpreter .stdlib_path (name ), dest = cls .to_stdlib )
82
+
52
83
@property
53
84
def reload_code (self ):
54
85
result = super (CPython2macOsFramework , self ).reload_code
55
86
result = dedent (
56
87
"""
57
88
# the bundled site.py always adds the global site package if we're on python framework build, escape this
58
89
import sysconfig
59
-
60
90
config = sysconfig.get_config_vars()
61
91
before = config["PYTHONFRAMEWORK"]
62
92
try:
@@ -71,6 +101,34 @@ def reload_code(self):
71
101
return result
72
102
73
103
104
+ class CPython3macOsFramework (CPythonmacOsFramework , CPython3 , CPythonPosix ):
105
+ @classmethod
106
+ def image_ref (cls , interpreter ):
107
+ return Path (interpreter .prefix ) / "Python3"
108
+
109
+ def current_mach_o_image_path (self ):
110
+ return "@executable_path/../../../../Python3"
111
+
112
+ @property
113
+ def reload_code (self ):
114
+ result = super (CPython3macOsFramework , self ).reload_code
115
+ result = dedent (
116
+ """
117
+ # the bundled site.py always adds the global site package if we're on python framework build, escape this
118
+ import sys
119
+ before = sys._framework
120
+ try:
121
+ sys._framework = None
122
+ {}
123
+ finally:
124
+ sys._framework = before
125
+ """ .format (
126
+ result
127
+ )
128
+ )
129
+ return result
130
+
131
+
74
132
def fix_mach_o (exe , current , new , max_size ):
75
133
"""
76
134
https://en.wikipedia.org/wiki/Mach-O
0 commit comments