8
8
# except according to those terms.
9
9
10
10
import os
11
- import shutil
12
11
import subprocess
13
12
import tempfile
14
13
from typing import Optional
15
14
import urllib
16
15
import zipfile
17
- from distutils .version import LooseVersion
18
16
19
- import six
20
17
from .. import util
21
18
from .base import Base
22
19
23
20
DEPS_URL = "https://github.com/servo/servo-build-deps/releases/download/msvc-deps/"
24
21
DEPENDENCIES = {
25
- "cmake" : "3.14.3" ,
26
22
"llvm" : "15.0.5" ,
27
23
"moztools" : "3.2" ,
28
- "ninja" : "1.7.1" ,
29
- "nuget" : "08-08-2019" ,
30
24
"openssl" : "111.3.0+1.1.1c-vs2017-2019-09-18" ,
31
25
"gstreamer-uwp" : "1.16.0.5" ,
32
26
"openxr-loader-uwp" : "1.0" ,
38
32
DEPENDENCIES_DIR = os .path .join (util .get_target_dir (), "dependencies" )
39
33
40
34
35
+ def get_dependency_dir (package ):
36
+ """Get the directory that a given Windows dependency should extract to."""
37
+ return os .path .join (DEPENDENCIES_DIR , package , DEPENDENCIES [package ])
38
+
39
+
41
40
class Windows (Base ):
42
41
def __init__ (self , triple : str ):
43
42
super ().__init__ (triple )
@@ -49,64 +48,65 @@ def executable_suffix(self):
49
48
def library_path_variable_name (self ):
50
49
return "LIB"
51
50
52
- @staticmethod
53
- def cmake_already_installed (required_version : str ) -> bool :
54
- cmake_path = shutil .which ("cmake" )
55
- if not cmake_path :
56
- return False
57
-
58
- output = subprocess .check_output ([cmake_path , "--version" ])
59
- cmake_version_output = six .ensure_str (output ).splitlines ()[0 ]
60
- installed_version = cmake_version_output .replace ("cmake version " , "" )
61
- return LooseVersion (installed_version ) >= LooseVersion (required_version )
62
-
63
51
@classmethod
64
- def prepare_file (cls , deps_dir : str , zip_path : str , full_spec : str ):
52
+ def download_and_extract_dependency (cls , zip_path : str , full_spec : str ):
65
53
if not os .path .isfile (zip_path ):
66
- zip_url = "{}{}.zip" . format ( DEPS_URL , urllib .parse .quote (full_spec ))
54
+ zip_url = f" { DEPS_URL } { urllib .parse .quote (full_spec )} .zip"
67
55
util .download_file (full_spec , zip_url , zip_path )
68
56
69
- print ("Extracting {}..." .format (full_spec ), end = "" )
57
+ zip_dir = os .path .dirname (zip_path )
58
+ print (f"Extracting { full_spec } to { zip_dir } ..." , end = "" )
70
59
try :
71
- util .extract (zip_path , deps_dir )
60
+ util .extract (zip_path , zip_dir )
72
61
except zipfile .BadZipfile :
73
- print ("\n Error: %s .zip is not a valid zip file, redownload..." % full_spec )
62
+ print (f "\n Error: { full_spec } .zip is not a valid zip file, redownload..." )
74
63
os .remove (zip_path )
75
- cls .prepare_file ( deps_dir , zip_path , full_spec )
64
+ cls .download_and_extract_dependency ( zip_path , full_spec )
76
65
else :
77
66
print ("done" )
78
67
79
- def _platform_bootstrap (self , cache_dir : str , _force : bool = False ) -> bool :
80
- deps_dir = os .path .join (cache_dir , "msvc-dependencies" )
81
-
82
- def get_package_dir (package , version ) -> str :
83
- return os .path .join (deps_dir , package , version )
84
-
85
- to_install = {}
86
- for package , version in DEPENDENCIES .items ():
87
- # Don't install CMake if it already exists in PATH
88
- if package == "cmake" and self .cmake_already_installed (version ):
89
- continue
90
-
91
- if not os .path .isdir (get_package_dir (package , version )):
92
- to_install [package ] = version
68
+ def _platform_bootstrap (self , force : bool = False ) -> bool :
69
+ installed_something = self .passive_bootstrap ()
93
70
71
+ try :
72
+ choco_config = os .path .join (util .SERVO_ROOT , "support" , "windows" , "chocolatey.config" )
73
+
74
+ # This is the format that PowerShell wants arguments passed to it.
75
+ cmd_exe_args = f"'/K','choco','install','-y','{ choco_config } '"
76
+ if force :
77
+ cmd_exe_args += ",'-f'"
78
+
79
+ print (cmd_exe_args )
80
+ subprocess .check_output ([
81
+ "powershell" , "Start-Process" , "-Wait" , "-verb" , "runAs" ,
82
+ "cmd.exe" , "-ArgumentList" , f"@({ cmd_exe_args } )"
83
+ ]).decode ("utf-8" )
84
+ except subprocess .CalledProcessError as e :
85
+ print ("Could not run chocolatey. Follow manual build setup instructions." )
86
+ raise e
87
+
88
+ return installed_something
89
+
90
+ def passive_bootstrap (self ) -> bool :
91
+ """A bootstrap method that is called without explicitly invoking `./mach bootstrap`
92
+ but that is executed in the process of other `./mach` commands. This should be
93
+ as fast as possible."""
94
+ to_install = [package for package in DEPENDENCIES if
95
+ not os .path .isdir (get_dependency_dir (package ))]
94
96
if not to_install :
95
97
return False
96
98
97
99
print ("Installing missing MSVC dependencies..." )
98
- for package , version in to_install . items () :
99
- full_spec = "{}-{}" .format (package , version )
100
+ for package in to_install :
101
+ full_spec = "{}-{}" .format (package , DEPENDENCIES [ package ] )
100
102
101
- package_dir = get_package_dir (package , version )
103
+ package_dir = get_dependency_dir (package )
102
104
parent_dir = os .path .dirname (package_dir )
103
105
if not os .path .isdir (parent_dir ):
104
106
os .makedirs (parent_dir )
105
107
106
- self .prepare_file (deps_dir , package_dir + ".zip" , full_spec )
107
-
108
- extracted_path = os .path .join (deps_dir , full_spec )
109
- os .rename (extracted_path , package_dir )
108
+ self .download_and_extract_dependency (package_dir + ".zip" , full_spec )
109
+ os .rename (os .path .join (parent_dir , full_spec ), package_dir )
110
110
111
111
return True
112
112
0 commit comments