1
1
"""Installer CLI."""
2
2
3
3
import argparse
4
+ import compileall
4
5
import distutils .dist
5
6
import os
6
7
import os .path
8
+ import py_compile
7
9
import sys
8
10
import sysconfig
9
11
14
16
from installer ._compat .typing import TYPE_CHECKING
15
17
16
18
if TYPE_CHECKING :
17
- from typing import Dict , Optional , Sequence
19
+ from typing import Any , Dict , List , Optional , Sequence , Union
18
20
19
21
from installer ._compat .typing import Text
22
+ from installer .records import RecordEntry
20
23
21
24
22
25
def main_parser (): # type: () -> argparse.ArgumentParser
@@ -31,6 +34,23 @@ def main_parser(): # type: () -> argparse.ArgumentParser
31
34
default = "/" ,
32
35
help = "destination directory" ,
33
36
)
37
+ if sys .version_info >= (3 ,):
38
+ parser .add_argument (
39
+ "--optimize" ,
40
+ "-o" ,
41
+ nargs = "*" ,
42
+ metavar = "level" ,
43
+ type = int ,
44
+ default = [0 , 1 ],
45
+ help = "optimization level(s) (default=0, 1)" ,
46
+ )
47
+ else :
48
+ parser .add_argument (
49
+ "--optimize" ,
50
+ "-o" ,
51
+ action = "store_true" ,
52
+ help = "enable optimization" ,
53
+ )
34
54
return parser
35
55
36
56
@@ -53,6 +73,35 @@ def get_scheme_dict(distribution_name): # type: (Text) -> Dict[str, str]
53
73
return scheme_dict
54
74
55
75
76
+ def _compile_records (record_dict , scheme_dict , compile_args ):
77
+ # type: (Dict[str, List[RecordEntry]], Dict[str, str], Dict[str, Any]) -> None
78
+ for scheme , records in record_dict .items ():
79
+ if scheme not in ("purelib" , "platlib" ):
80
+ continue
81
+ for record in records :
82
+ target_path = os .path .join (scheme_dict [scheme ], record .path )
83
+ compileall .compile_file (target_path , ** compile_args )
84
+
85
+
86
+ def generate_bytecode (record_dict , scheme_dict , levels , stripdir = None ):
87
+ # type: (Dict[str, List[RecordEntry]], Dict[str, str], Union[List[int], bool], Optional[str]) -> None
88
+ """Generate bytecode for Python files."""
89
+ if sys .version_info [0 ] == 2 :
90
+ return _compile_records (record_dict , scheme_dict , {})
91
+
92
+ assert isinstance (levels , list )
93
+
94
+ compile_args = {} # type: Dict[str, Any]
95
+ if stripdir :
96
+ compile_args ["stripdir" ] = stripdir
97
+ if sys .version_info >= (3 , 7 ):
98
+ compile_args ["invalidation_mode" ] = py_compile .PycInvalidationMode .CHECKED_HASH
99
+
100
+ for level in levels :
101
+ compile_args ["optimize" ] = level
102
+ _compile_records (record_dict , scheme_dict , compile_args )
103
+
104
+
56
105
def main (cli_args , program = None ):
57
106
# type: (Sequence[str], Optional[str]) -> None
58
107
"""Process arguments and perform the install."""
@@ -61,6 +110,8 @@ def main(cli_args, program=None):
61
110
parser .prog = program
62
111
args = parser .parse_args (cli_args )
63
112
113
+ bytecode_stripdir = None # type: Optional[str]
114
+
64
115
with installer .sources .WheelFile .open (args .wheel ) as source :
65
116
scheme_dict = get_scheme_dict (source .distribution )
66
117
@@ -76,13 +127,17 @@ def main(cli_args, program=None):
76
127
name : os .path .join (args .destdir , os .path .relpath (value , root ))
77
128
for name , value in scheme_dict .items ()
78
129
}
130
+ bytecode_stripdir = root
79
131
80
132
destination = installer .destinations .SchemeDictionaryDestination (
81
133
scheme_dict ,
82
134
sys .executable ,
83
135
installer .utils .get_launcher_kind (),
84
136
)
85
- installer .install (source , destination , {})
137
+ records = installer .install (source , destination , {})
138
+
139
+ if args .optimize :
140
+ generate_bytecode (records , scheme_dict , args .optimize , bytecode_stripdir )
86
141
87
142
88
143
def entrypoint (): # type: () -> None
0 commit comments